package it.netsphere.nswing.comp;

import java.awt.Toolkit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;

import ognl.Ognl;

public class NSTextAreaRegExp extends JTextArea {
	private static final long serialVersionUID = 5541208668848898981L;

	public NSTextAreaRegExp() {
		getDocument().addDocumentListener(new MyDocumentListener());
	}

	private String regExp;

	public String getRegExp() {
		return regExp;
	}

	public void setRegExp(String regExp) {
		this.regExp = regExp;
		pattern = null;
	}

	private Pattern pattern;

	private Pattern getPattern() {
		if (pattern == null && getRegExp() != null) {
			pattern = Pattern.compile(getRegExp());
		}

		return pattern;
	}

	/**
	 * Create a new document model for this control that only accepts integral
	 * values.
	 * 
	 * @return The new document model.
	 */
	@Override
	protected Document createDefaultModel() {
		return new RegExpDocument();
	}

	/**
	 * This document only allows integral values to be added to it.
	 */
	private class RegExpDocument extends PlainDocument {
		private static final long serialVersionUID = 3405892854619203816L;

		@Override
		public void insertString(int offs, String str, AttributeSet a)
				throws BadLocationException {

			if (getPattern() == null) {
				super.insertString(offs, str, a);
				return;
			}

			try {
				String s = NSTextAreaRegExp.this.getText();
				if (s == null)
					s = str;
				else
					s = (offs > 0 ? s.substring(0, offs) : "") + str
							+ (s.substring(offs));

				Matcher m = getPattern().matcher(s);
				if (m.matches())
					super.insertString(offs, str, a);
			} catch (NumberFormatException ex) {
				Toolkit.getDefaultToolkit().beep();
			}
		}
	}

	private Object userObject;

	public Object getUserObject() {
		return userObject;
	}

	public void setUserObject(Object userObject) {
		this.userObject = userObject;
		updateInternal();
	}

	private String userObjectField;

	public String getUserObjectField() {
		return userObjectField;
	}

	public void setUserObjectField(String userObjectField) {
		this.userObjectField = userObjectField;
		updateInternal();
	}

	private boolean updating = false;

	private void updateInternal() {
		if (getUserObject() == null)
			return;
		if (getUserObjectField() == null)
			return;

		try {
			updating = true;
			String s = (String) Ognl.getValue(getUserObjectField(),
					getUserObject());
			setText(s);
			// Ognl.setValue( getUserObjectField() , getUserObject(),
			// getText());
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			updating = false;
		}
	}

	private void updateTouserObject() {
		if (updating)
			return;
		if (getUserObject() == null)
			return;
		if (getUserObjectField() == null)
			return;

		try {
			Ognl.setValue(getUserObjectField(), getUserObject(), getText());
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
		}
	}

	private class MyDocumentListener implements DocumentListener {

		@Override
		public void changedUpdate(DocumentEvent e) {
			updateTouserObject();
		}

		@Override
		public void insertUpdate(DocumentEvent e) {
			updateTouserObject();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			updateTouserObject();
		}

	}

}
